package com.property.manage.service.rent;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.guardchina.framework.util.exception.SystemException;
import com.guardchina.framework.util.utils.NumberToCn;
import com.property.manage.dao.rent.HouseArrearsMapper;
import com.property.manage.enums.WalletType;
import com.property.manage.model.print.ArrearsPayBillVo;
import com.property.manage.model.rent.HouseArrearsEntity;
import com.property.manage.model.rent.HouseArrearsVo;
import com.property.manage.model.rent.RentEntity;
import com.property.manage.model.rent.RentPaymentEntity;
import com.property.manage.model.resource.Building;
import com.property.manage.model.system.User;
import com.property.manage.model.village.Village;
import com.property.manage.service.flowingWater.WalletService;
import com.property.manage.service.resource.BuildingService;
import com.property.manage.service.system.SnowflakeIdWorker;
import com.property.manage.service.system.UserService;
import com.property.manage.service.village.VillageService;
import com.property.manage.util.ExportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Service
@Slf4j
public class HouseArrearsService {
    @Autowired
    private HouseArrearsMapper houseArrearsMapper;
    @Autowired
    private WalletService walletService;

    @Autowired
    private UserService userService;

    @Autowired
    private VillageService  villageService;

    @Autowired
    private BuildingService buildingService;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private RentPaymentService rentPaymentService;

    @Autowired
    private RentService rentService;

    @Value("${timed.patee}")
    private String patee;

    @Value("${timed.receiveUnit}")
    private String receiveUnit;

    public CustomPage<HouseArrearsVo> page(Long pageNo, Long pageSize, Integer villageId, Integer building, Integer unit, String roomNumber,
                                           String startTime, String endTime) {
        Page<HouseArrearsVo> page = new Page<>(pageNo, pageSize);
        IPage<HouseArrearsVo> village = houseArrearsMapper.getHouseRentPage(page, villageId, building, unit, roomNumber, startTime, endTime);
        return new CustomPage<>(village);
    }


    public void add(List<HouseArrearsEntity> list) {
        houseArrearsMapper.batchInsert(list);
    }

    public HouseArrearsVo getByBuildingId(Integer buidlingId){
        HouseArrearsVo byBuildingId = houseArrearsMapper.getByBuildingId(buidlingId);
        QueryWrapper<HouseArrearsEntity> qw=new QueryWrapper<>();
        qw.eq("building_id",buidlingId);
        qw.eq("state", 1);
        List<HouseArrearsEntity> arrearsEntities = houseArrearsMapper.selectList(qw);
        byBuildingId.setEntities(arrearsEntities);
        BigDecimal balance = walletService.findBalance(buidlingId, WalletType.RENT);
        byBuildingId.setBalance(balance);
        return byBuildingId;
    }

    public void batchUpdate(List<HouseArrearsEntity> list){
        houseArrearsMapper.batchUpdate(list);
    }


    @Transactional(rollbackFor = Exception.class)
    public ArrearsPayBillVo charge(Integer userId, Integer buildingId, String arrearsIds, BigDecimal totalMoney, BigDecimal chargeMoney, Integer payType, Boolean useStorage, Boolean storageReturn, Boolean print, String remark){

        log.info("房屋租金欠费收取：userId[{}], buildingId[{}], arrearsIds[{}], totalMoney[{}], chargeMoney[{}], payType[{}], useStorage[{}], storageReturn[{}], print[{}], remark[{}]", userId, buildingId, arrearsIds, totalMoney, chargeMoney, payType, useStorage, storageReturn, print, remark);

        List<Integer> arrearsIdList = new Gson().fromJson(arrearsIds, new TypeToken<List<Integer>>(){}.getType());

        List<HouseArrearsEntity> arrearsList = getList(arrearsIdList);

        BigDecimal dbTotalMoney = arrearsList.stream().map(HouseArrearsEntity::getTotalMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        String remarks = arrearsList.stream().
                map(HouseArrearsEntity::getTime).
                reduce((s1, s2) -> s1 + "、" + s2).
//                reduce((s1, s2) -> s1  + s2).

                orElse("");
        remarks = StringUtils.substring(remarks,0, 4) + StringUtils.substring(remarks,5, 7);
        remarks = remarks + "欠费收取" ;

        if(totalMoney.compareTo(dbTotalMoney) != 0){
            throw new SystemException("应收金额不一致",String.format("dbTotalMoney[%s]", dbTotalMoney));
        }

        //转存预存,默认为零
        BigDecimal advanceReturn = BigDecimal.ZERO;
        //使用预存，默认为零
        BigDecimal advanceUse = BigDecimal.ZERO;
        //收款剩余金额
        BigDecimal remainMoney = chargeMoney.subtract(totalMoney);
        //获取预存余额
        BigDecimal balance = walletService.findBalance(buildingId, WalletType.RENT);

        //如果收款剩余金额大于等于0,且转存，则转存金额为收款剩余金额
        if(remainMoney.compareTo(BigDecimal.ZERO) >= 0 && storageReturn){
            advanceReturn = remainMoney;
        }else if (remainMoney.compareTo(BigDecimal.ZERO) < 0){
            //收款剩余金额小于零，且使用预存
            if(useStorage){
                //预存余额不足
                if(balance.add(remainMoney).compareTo(BigDecimal.ZERO) < 0){
                    throw new BusinessException("缴费金额不足",String.format("使用预存，预存余额[%s], 剩余缴费[%s]", balance, remainMoney.abs()));
                }else {
                    //使用的预存为，剩余的未缴费用
                    advanceUse = remainMoney.abs();
                }
            }else {
                throw new BusinessException("缴费金额不足",String.format("不使用预存，剩余缴费[%s]", remainMoney.abs()));
            }
        }

        User user = userService.getUser(userId);
        Building building = buildingService.findBuilding(buildingId);
        Village village = villageService.findVillage(building.getVillageId());

        String billNo = snowflakeIdWorker.nextId() + "";

        BigDecimal money = arrearsList.stream().map(HouseArrearsEntity::getMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        BigDecimal propertyFee = arrearsList.stream().map(HouseArrearsEntity::getPropertyFee).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        BigDecimal otherFee = arrearsList.stream().map(HouseArrearsEntity::getOtherFee).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

        /*User user, Integer villageId, Integer buildingId, Integer type,
                BigDecimal money, BigDecimal propertyFee, BigDecimal otherFee, BigDecimal total,
                BigDecimal preDeposit, BigDecimal cash, BigDecimal returnDeposit, String billNo, String remark*/
        Integer payId = rentPaymentService.add(user, arrearsList.get(0).getRentId(), village.getId(), buildingId, payType, money, propertyFee, otherFee,
                totalMoney, advanceUse, chargeMoney, advanceReturn, billNo, remarks, totalMoney, RentPaymentEntity.OTHER_TYPE_ARREARS);

        charge(arrearsIdList, payId);

        if(print){
            ArrearsPayBillVo bill = new ArrearsPayBillVo();


            RentEntity rentEntity = rentService.getById(arrearsList.get(0).getRentId());



            bill.setTitle(patee + "收款收据");
            bill.setBillNo(billNo);
            bill.setVillageName(village.getName());
            bill.setAddress(buildingService.findAddress(building));
            bill.setOwnerName(rentEntity.getName());
            bill.setPayTime(LocalDate.now());
            bill.setPayee(user.getUserName());
            bill.setReceiveUnit(receiveUnit);

            List<ArrearsPayBillVo.BillDetail> billDetails = arrearsList.stream().map(arrears -> {
                ArrearsPayBillVo.BillDetail billDetail = new ArrearsPayBillVo.BillDetail();

                billDetail.setFeeType("房屋租金");
                billDetail.setYearMonth(arrears.getTime());
                billDetail.setMoney(arrears.getTotalMoney());
                billDetail.setPropertyMoney(arrears.getPropertyFee());
                billDetail.setRentMoney(arrears.getMoney());
                billDetail.setOtherMoney(arrears.getOtherFee());
                billDetail.setRemark("欠费缴纳");

                return billDetail;
            }).collect(Collectors.toList());

            bill.setBillDetails(billDetails);

            bill.setTotalAmount(totalMoney);
            bill.setTotalOtherMoney(otherFee);
            bill.setTotalRentMoney(money);
            bill.setTotalPropertyMoney(propertyFee);
            bill.setReceiveAmount(chargeMoney);
            bill.setDeductionAmount(BigDecimal.ZERO);
            bill.setPreAmount(balance);
            bill.setThisAmount(advanceUse);
            BigDecimal currentBalance = walletService.findBalance(buildingId, WalletType.RENT);
            bill.setReturnAmount(currentBalance);
            bill.setRealAmount(totalMoney);
            bill.setChineseAmount(NumberToCn.number2Cn(totalMoney));


            return bill;
        }else{
            return null;
        }
    }

    public void undoCharge(Integer payId){
        UpdateWrapper<HouseArrearsEntity> wrapper = new UpdateWrapper<>();
        wrapper.set("state", 1);
        wrapper.eq("pay_id", payId);

        houseArrearsMapper.update(null, wrapper);
    }

    private void charge(List<Integer> arrearsIdList, Integer payId) {

        UpdateWrapper<HouseArrearsEntity> wrapper = new UpdateWrapper<>();

        wrapper.in("id", arrearsIdList);
        wrapper.set("state", 2);
        wrapper.set("pay_id", payId);


        //更新缴费时间
        String chargeTime = DateFormatUtils.format(new Date(), "yyyy-MM");
        wrapper.set("charge_time", chargeTime);

        houseArrearsMapper.update(null, wrapper);
    }

    public void download(Integer villageId, String startTime, String endTime, HttpServletRequest request, HttpServletResponse response) {

        String str = "房租欠费报表";
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet(str);
        //创建第一行
        XSSFRow row = sheet.createRow(0);
        //设置表头格式
        List<String> titles = Arrays.asList("付款方","月份", "物业费", "租金", "其他费用", "总计");

        for (int i = 0; i <= 5; i++) {
            sheet.setColumnWidth(i, 4500);
            row.createCell(i).setCellValue(titles.get(i));

        }

        List<HouseArrearsEntity> rentPage = houseArrearsMapper.getHouseRent(villageId, null, null, null, startTime, endTime);
        //将所有单元格设置成文本格式
        if (!rentPage.isEmpty()){
            for (int i = 1; i <= (rentPage.size()); i++) {
                HouseArrearsEntity vo = rentPage.get(i - 1);
                XSSFRow row1 = sheet.createRow(i);
                row1.createCell(0).setCellValue(vo.getPayName());
                row1.createCell(1).setCellValue(vo.getTime());
                row1.createCell(2).setCellValue(vo.getPropertyFee().doubleValue());
                row1.createCell(3).setCellValue(vo.getMoney().doubleValue());
                row1.createCell(4).setCellValue(vo.getOtherFee().doubleValue());
                row1.createCell(5).setCellValue(vo.getTotalMoney().doubleValue());

            }
        }
        String fileName = "房屋租金欠费报表.xlsx";
        ExportUtil.exportExcel(request, response, fileName, workbook);

    }

    private List<HouseArrearsEntity> getList(List<Integer> arrearsIdList) {

        QueryWrapper<HouseArrearsEntity> wrapper = new QueryWrapper<>();
        wrapper.in("id", arrearsIdList);

        return houseArrearsMapper.selectList(wrapper);
    }
}
